home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / TextView.C < prev    next >
C/C++ Source or Header  |  1990-12-06  |  19KB  |  816 lines

  1. //$TextView$
  2. #include "TextView.h"
  3.  
  4. #include "TextCmd.h"
  5. #include "CmdNo.h"
  6. #include "String.h"
  7. #include "View.h"
  8. #include "BlankWin.h"
  9. #include "Menu.h"
  10. #include "Error.h"
  11. #include "ChangeDialog.h"
  12. #include "Document.h"
  13. #include "RegularExp.h"
  14. #include "ClipBoard.h"
  15. #include "TextFormatter.h"
  16. #include "ObjectTable.h"
  17.  
  18. static u_short CaretBits[]= {
  19. #   include "images/Caret.image"
  20. };  
  21.  
  22. const int cCaretHt = 4,
  23.       cCaretWd = 7;
  24.  
  25. static Bitmap *CaretImage;
  26.  
  27. void SwapSelPoints(SelPoint &p1, SelPoint &p2)
  28. {
  29.     SelPoint tmp;
  30.  
  31.     tmp= p1; p1= p2; p2= tmp;
  32. }
  33.  
  34. //----- TextView Methods --------------------------------------------------
  35.  
  36. MetaImpl(TextView, (TB(updateSelection), TB(inTextSelector), 
  37.     TP(stopChars), TP(Typeing), TP(findChange), 
  38.     TP(scratchText), T(start.ch), T(start.line), T(start.viewp),
  39.     T(end.ch), T(end.line), T(end.viewp), 0));
  40.  
  41. TextView::TextView(EvtHandler *eh, Rectangle r, Text *t, eTextJust m, eSpacing sp, 
  42.                bool doWrap, TextViewFlags fl, Point b, int id)
  43.                 : StaticTextView(eh, r, t, m, sp, doWrap, fl, b, id) 
  44. {
  45.     Init();
  46. }
  47.  
  48. void TextView::InitNew()
  49. {
  50.     View::InitNew();
  51.     inTextSelector= FALSE;
  52. }  
  53.  
  54. void TextView::Init()
  55. {
  56.     PrivSetSelection(0, 0, FALSE);
  57.     Typeing= 0;
  58.     stopChars= 0;
  59.     updateSelection= TRUE;
  60.     text->AddObserver(this);
  61.     scratchText= text->GetScratchText(cMaxBatchedIns);
  62.     findChange= 0;
  63. }
  64.  
  65. TextView::~TextView()
  66. {
  67.     if (text)
  68.     text->RemoveObserver(this);
  69.     SafeDelete(stopChars);
  70.     if (findChange)
  71.     findChange->Close();
  72.     SafeDelete(findChange);
  73.     SafeDelete(scratchText);
  74. }
  75.  
  76. void TextView::InvalidateSelection()
  77. {
  78.     if (AnySelection())
  79.     InvalidateRange(start.line, start.viewp, end.line, end.viewp);
  80. }
  81.  
  82. void TextView::Draw(Rectangle r)
  83. {
  84.     if (GrHasColor() && AnySelection())
  85.     Invert(start.line, start.viewp, end.line, end.viewp);
  86.     StaticTextView::Draw(r);
  87.     DrawCaret(start.viewp, start.line, On);
  88.     if (!GrHasColor() && AnySelection())
  89.     Invert(start.line, start.viewp, end.line, end.viewp);
  90. }
  91.  
  92. static Ink *caretColor;
  93.     
  94. void TextView::DrawCaret(Point p, int line, HighlightState)
  95. {
  96.     if (! inTextSelector && AnySelection() && Caret()) {
  97.     int bh= BaseHeight(line);
  98.     p+= GetInnerOrigin();
  99.  
  100.     if (caretColor == 0) {
  101.         if (GrHasColor())
  102.         caretColor= new RGBColor(255, 0, 0);
  103.         else
  104.         caretColor= ePatXor;
  105.     }
  106.     
  107.     if (LineHeight(line) - bh >= cCaretHt) {
  108.         Rectangle r(p.x-cCaretHt, p.y+bh, cCaretWd, cCaretHt);
  109.         if (CaretImage == 0)
  110.         ObjectTable::AddRoot(
  111.             CaretImage= new Bitmap(Point(cCaretWd, cCaretHt), CaretBits));
  112.         GrPaintBitMap(r, CaretImage, caretColor);
  113.     }
  114.     p.x--;
  115.     GrPaintLine(caretColor, 1, eDefaultCap, Point(p.x, p.y), Point(p.x, p.y+bh));
  116.     }
  117. }
  118.  
  119. //---- highlight the characters in the given range -----------------------
  120.  
  121. void TextView::Invert(int from, Point fp, int to, Point tp)
  122. {
  123.     if (AnySelection() && !Caret()) {
  124.     Rectangle r;
  125.     
  126.     if ((from == to && fp.x > tp.x) || from > to) { // normalize range
  127.         swap(from, to);
  128.         Swap(fp, tp);   
  129.     }
  130.     
  131.     if (from == to) {
  132.         r= Rectangle(LineToPoint(from)+Point (fp.x,0),
  133.                Point(tp.x-fp.x, LineHeight(from)));
  134.         GrPaintRect(r+GetInnerOrigin(), gHighlightColor);
  135.         return;
  136.     }
  137.     r= Rectangle(LineToPoint(from)+ Point(fp.x,0),
  138.               Point(GetInnerExtent().x-fp.x, LineHeight(from)));
  139.     GrPaintRect(r+GetInnerOrigin(), gHighlightColor);
  140.     r= Rectangle(LineToPoint(from + 1), Point(GetInnerExtent().x,
  141.               LineToPoint(to).y - LineToPoint(from + 1).y));
  142.     GrPaintRect(r+GetInnerOrigin(), gHighlightColor);
  143.     r= Rectangle(LineToPoint(to), Point(tp.x, LineHeight(to)));
  144.     GrPaintRect(r+GetInnerOrigin(), gHighlightColor);
  145.     }
  146. }
  147.  
  148. void TextView::Reformat()
  149. {
  150.     StaticTextView::Reformat();
  151.     if (AnySelection())
  152.     SetSelection(start.ch, end.ch, FALSE);
  153. }
  154.  
  155. void TextView::SetNoSelection(bool redraw)
  156. {
  157.     if (AnySelection()) {
  158.     InvalidateSelection();
  159.     start.ch= end.ch= -1;
  160.     if (redraw)
  161.         UpdateEvent();
  162.     }
  163. }
  164.  
  165. void TextView::PrivSetSelection(SelPoint s, SelPoint e, bool redraw)
  166. {
  167.     InvalidateSelection();          // invalidate old selection
  168.     start= s;
  169.     end= e;
  170.     InvalidateSelection();          // invalidate new selection
  171.     if (redraw)
  172.     UpdateEvent();
  173. }
  174.  
  175. void TextView::PrivSetSelection(int s, int e, bool redraw)
  176. {
  177.     SelPoint sp, ep;
  178.     int size= text->Size();
  179.     
  180.     sp.ch= range(0, size, s);
  181.     ep.ch= range(0, size, e);
  182.     CharToPos(sp.ch, &sp.line, &sp.viewp);
  183.     if (sp.ch != ep.ch)
  184.     CharToPos(ep.ch, &ep.line, &ep.viewp);
  185.     else
  186.     ep= sp;
  187.     PrivSetSelection(sp, ep, redraw);
  188. }
  189.  
  190. void TextView::SetSelection(int s, int e, bool redraw)
  191. {
  192.     DoneTypeing();
  193.     PrivSetSelection(s, e, redraw);
  194. }
  195.  
  196. void TextView::SelectionAsString(byte *buf, int max)
  197. {
  198.     GetText()->CopyInStr(buf, max, start.ch, end.ch);
  199. }
  200.  
  201. Text *TextView::SelectionAsText()
  202. {
  203.     return text->Save(start.ch, end.ch);
  204. }
  205.  
  206. void TextView::RevealSelection()
  207. {
  208.     if (AnySelection()) {
  209.     Rectangle r= SelectionRect().Expand(8);
  210.     RevealRect(r, r.extent);
  211.     }
  212. }
  213.      
  214. Rectangle TextView::SelectionRect()
  215. {
  216.     if (AnySelection()) {
  217.     Point p(end.viewp.x+1, end.viewp.y + LineHeight(end.line));
  218.     Rectangle r= NormRect(start.viewp, p);
  219.     r.origin+= GetInnerOrigin();
  220.     return r;
  221.     }
  222.     return gRect0;
  223. }
  224.  
  225. Command *TextView::DoLeftButtonDownCommand(Point lp, Token t, int clicks)
  226. {
  227.     SelPoint oldStart, oldEnd;
  228.     TextRangeFP rf= CharacterRange;
  229.     
  230.     oldStart= start;
  231.     oldEnd= end;
  232.     formatter->ResumeFormat();
  233.     if (! Enabled())
  234.     return View::DoLeftButtonDownCommand(lp, t, clicks);
  235.     
  236.     Control(GetId(), cPartWantKbdFocus, this);
  237.     
  238.     if (clicks >= 3)
  239.     rf= ParagraphRange;
  240.     else if (clicks >= 2) 
  241.     rf= WordRange;
  242.  
  243.     if (t.Flags == eFlgShiftKey) 
  244.     return new ExtendRangeSelector(this, rf);  
  245.     
  246.     if (t.Flags == eFlgCntlKey && clicks == 1) 
  247.     return new CopyDragPasteSelector(this, oldStart.ch, oldEnd.ch); 
  248.  
  249.     if (t.Flags == (eFlgShiftKey|eFlgCntlKey) && clicks == 1)
  250.     return new QuickPasteSelector(this, oldStart.ch, oldEnd.ch);
  251.     
  252.     if (t.Flags == 0)
  253.     return new RangeSelector(this, rf);
  254.     return View::DoLeftButtonDownCommand(lp, t, clicks);
  255. }
  256.  
  257. void TextView::SetStopChars(char *stops)
  258. {
  259.     strreplace(&stopChars, stops);
  260. }
  261.  
  262. Command *TextView::DoKeyCommand(int ch, Point, Token token)
  263. {
  264.     int nDelete= 0;
  265.     Token t;
  266.     bool newCmd, delSelection;       // delete the selection only
  267.  
  268.     if (!Writeable())
  269.     return gNoChanges;
  270.     if (token.Code == 'd' + 128 && gDebug) {
  271.     Dump();
  272.     return gNoChanges;
  273.     }
  274.  
  275.     GrSetCursor(eCrsNone);
  276.     //---- map \r to to \n ???
  277.     if (ch == '\r')
  278.     ch= '\n';
  279.  
  280.     newCmd= (Typeing == 0 || Typeing->completed); // start new typing sequence?
  281.  
  282.     if (newCmd) {
  283.     if (Typeing)
  284.         Typeing->SetFlag(eCmdDoDelete);
  285.     Typeing= new TypeingCommand(this, cTYPEING, "typing");
  286.     }
  287.  
  288.     delSelection= (newCmd && !Caret());
  289.     if (ch != gBackspace || delSelection) {     
  290.     for (;;) {
  291.         if (ch != gBackspace) {
  292.         Typeing->AddChar();
  293.         scratchText->Append(ch);
  294.         }
  295.         if (scratchText->Size() == cMaxBatchedIns)
  296.         break;
  297.         t= gWindow->ReadEvent(0);
  298.         if (t.IsAscii() && (byte)t.Code != gBackspace 
  299.             // do not batch stopChars
  300.             && !(stopChars && index(stopChars, (byte)t.Code)) 
  301.             && ! TestFlag(eTextViewNoBatch)) {
  302.         ch= (byte) t.Code;
  303.         } else {
  304.         gWindow->PushBackEvent(t);
  305.         break;
  306.         } 
  307.     }
  308.     Paste(scratchText);
  309.     scratchText->Empty();
  310.     } else {
  311.     for (;;) {
  312.         Typeing->DelChar();
  313.         nDelete++;
  314.         t= gWindow->ReadEvent(0);
  315.         if ((byte) t.Code != gBackspace) {
  316.         gWindow->PushBackEvent(t);
  317.         break;
  318.         } 
  319.     } 
  320.     DelChar(nDelete);
  321.     }
  322.     RevealSelection();
  323.     return Typeing;    
  324. }
  325.  
  326. Command *TextView::DoCursorKeyCommand(EvtCursorDir cd, Point p, Token)
  327. {
  328.     int charNo= 0;
  329.  
  330.     if (!Enabled())
  331.     return gNoChanges;
  332.     switch (cd) {
  333.     case eCrsLeft:
  334.     charNo= start.ch-1;
  335.     break;
  336.     case eCrsRight:
  337.     charNo= end.ch+1;
  338.     break;
  339.     case eCrsUp:
  340.     formatter->ResumeFormat();
  341.     charNo= CursorPos(start.ch, start.line, cd, p);
  342.     break;
  343.     case eCrsDown:
  344.     formatter->ResumeFormat();
  345.     charNo= CursorPos(end.ch, end.line, cd, p);
  346.     break;
  347.     }
  348.     SetSelection(charNo, charNo);
  349.     RevealSelection();
  350.     return gNoChanges;
  351. }
  352.  
  353. int TextView::CursorPos(int at, int line, EvtCursorDir d, Point p)
  354. {
  355.     int charNo;
  356.     Point basePoint,screenPoint;
  357.  
  358.     CharToPos (at, &line, &screenPoint);
  359.     if (d == eCrsDown)
  360.     line= min(nLines-1, line+1);
  361.     else
  362.     line= max(0, line-1);        
  363.     basePoint= LineToPoint(line, TRUE) + Point(screenPoint.x, 0);
  364.     PointToPos(basePoint, &p, &line, &charNo);
  365.     return charNo;
  366. }
  367.  
  368. Command *TextView::DoOtherEventCommand(Point, Token t)
  369. {
  370.     if (t.Code == eEvtLocMove && TestFlag(eTextFormPreempt))
  371.     formatter->ResumeFormat();
  372.     return gNoChanges;
  373. }
  374.  
  375. GrCursor TextView::GetCursor(Point)
  376. {
  377.     return eCrsIBeam;
  378. }
  379.  
  380. Command *TextView::DoIdleCommand()
  381. {
  382.     if (TestFlag(eTextFormPreempt))
  383.     formatter->ResumeFormat(TRUE);
  384.     return View::DoIdleCommand();
  385. }
  386.  
  387. void TextView::DoneTypeing()
  388. {
  389.     if (Typeing)
  390.     Typeing->completed= TRUE;
  391.     text->ResetCurrentStyle();
  392.     formatter->ResumeFormat();
  393. }
  394.  
  395. void TextView::TypeingDeleted()
  396. {
  397.     Typeing= 0;  
  398. }
  399.  
  400. bool TextView::DeleteRequest(int,int)
  401. {
  402.     return TRUE;
  403. }
  404.  
  405. void TextView::Cut()
  406. {
  407.     if (!Writeable())
  408.     return; 
  409.     if (DeleteRequest(start.ch, end.ch) && AnySelection()) {
  410.     updateSelection= FALSE;
  411.     text->Cut(start.ch, end.ch);
  412.     updateSelection= TRUE;
  413.     PrivSetSelection(start.ch, start.ch, FALSE);
  414.     }
  415. }
  416.  
  417. void TextView::Copy(Text *t)
  418. {
  419.     text->Copy(t, start.ch, end.ch);
  420. }
  421.  
  422. void TextView::Paste(Text *t)
  423.     if (!Writeable())
  424.     return;
  425.     if ((!Caret() && !DeleteRequest(start.ch, end.ch)) || !AnySelection())
  426.     return;
  427.     // minor hack: if text is appended on the last line, 
  428.     // fake last line to reach a mark 
  429.     if (wrap && start.line == nLines-1) 
  430.     MarkAtLine(start.line)->len= cMaxInt;
  431.     updateSelection= FALSE;
  432.     text->Paste(t, start.ch, end.ch);
  433.     updateSelection= TRUE;
  434.     PrivSetSelection(start.ch+t->Size(), start.ch+t->Size(), FALSE);       
  435. }
  436.  
  437. Command *TextView::InsertText(Text *t)
  438. {
  439.     if (!Writeable())
  440.     return gNoChanges;
  441.  
  442.     bool newCmd;
  443.     newCmd= (Typeing == 0 || Typeing->completed); // start new typing sequence?
  444.  
  445.     if (newCmd) {
  446.     if (Typeing)
  447.         Typeing->SetFlag(eCmdDoDelete);
  448.     Typeing= new TypeingCommand(this, cTYPEING, "typing");
  449.     }
  450.  
  451.     Typeing->AddChar(t->Size());
  452.     Paste(t);
  453.     return Typeing;
  454. }
  455.  
  456. void TextView::DelChar (int n)
  457. {
  458.     int newStart= max(0, start.ch-n);
  459.     int changedLine= CharToLine(newStart);
  460.  
  461.     if (newStart == start.ch)
  462.     return;
  463.     if (newStart == 0 && start.ch == 0)
  464.     return;
  465.     if (DeleteRequest(newStart, start.ch)) {
  466.     updateSelection= FALSE;   
  467.     text->Cut(newStart, start.ch);
  468.     updateSelection= TRUE;
  469.     PrivSetSelection(newStart, newStart, FALSE);       
  470.     }
  471. }
  472.  
  473. Text *TextView::SetText(Text *t)
  474. {
  475.     Text *old= text;
  476.     old->RemoveObserver(this);
  477.     bool anySel= AnySelection();
  478.     PrivSetSelection(0, 0, FALSE); // reset old selection
  479.     text= t;    // should remove possible reference from a command object ???
  480.     SafeDelete(nextc);
  481.     nextc= text->MakeIterator();
  482.     SafeDelete(scratchText);
  483.     scratchText= text->GetScratchText(cMaxBatchedIns);
  484.     text->AddObserver(this);
  485.     Reformat();  
  486.     Send(GetId(), cPartReplacedText, 0);
  487.     SetSelection(0, 0, FALSE); // set new selection
  488.     if (!anySel)
  489.     SetNoSelection(FALSE);  
  490.     Typeing= 0;
  491.     return old;
  492. }       
  493.  
  494. void TextView::SetString(byte *str, int len)
  495. {
  496.     bool anySel= AnySelection();
  497.     PrivSetSelection(0, 0, FALSE); 
  498.     text->ReplaceWithStr(str, len);
  499.     Reformat();
  500.     Send(GetId(), cPartReplacedText, 0);
  501.     DoneTypeing();
  502.     PrivSetSelection(0, 0, FALSE); 
  503.     if (!anySel)
  504.     SetNoSelection(FALSE);  
  505.     Typeing= 0;
  506. }
  507.  
  508. void TextView::SetReadOnly(bool m)
  509. {
  510.     SetFlag(eTextViewReadOnly, m);
  511. }
  512.  
  513. bool TextView::GetReadOnly()
  514.     return TestFlag(eTextViewReadOnly); 
  515. }
  516.  
  517. void TextView::DoObserve(int, int part, void *what, Object *op)
  518. {
  519.     int d= 0, d1= 0;
  520.     
  521.     if (op == text && part != cPartSenderDied) {
  522.     TextChanges *tc= (TextChanges*)what;
  523.     int fl= CharToLine(tc->from), tl; // lines corresponding from, to
  524.     if (tc->from == tc->to)
  525.         tl= fl;
  526.     else 
  527.         tl= CharToLine(tc->to);
  528.  
  529.     switch (part) {
  530.     case eTextChangedRange:
  531.         ChangedAt(fl, tc->from, TRUE, tl);
  532.         if (updateSelection && AnySelection())
  533.         PrivSetSelection(tc->from, tc->to, TRUE);
  534.         break;
  535.  
  536.     case eTextDeleted:
  537.         marks->Cut(tc->from, tc->to - tc->from);
  538.         d = DeleteLines (fl, tl);
  539.         ChangedAt(fl, tc->from, d > 0);
  540.         if (updateSelection && AnySelection())
  541.         PrivSetSelection(tc->from, tc->from, TRUE);
  542.         break;
  543.  
  544.     case eTextReplaced:
  545.         if (tc->from != tc->to) {
  546.         marks->Cut(tc->from, tc->to - tc->from);
  547.         d1= DeleteLines(fl, tl);
  548.         }
  549.         marks->Paste(tc->from, tc->size); 
  550.         d= FormatInsertedText(fl, tc->from, tc->size);
  551.         ChangedAt(fl+d, tc->from, d > 0 || d1 > 0);
  552.         if (updateSelection && AnySelection()) {
  553.         int p= tc->from+tc->size;
  554.         PrivSetSelection(p, p, TRUE);   
  555.         }    
  556.         break;
  557.     }
  558.     if (TestFlag(eVObjLayoutCntl)) 
  559.         Control(GetId(), cPartChangedText, this);
  560.     Send(GetId(), cPartChangedText, this);    // notify observers of the textview   
  561.     }
  562. }
  563.  
  564. bool TextView::PrintOnWhenObserved(Object *from)
  565. {
  566.     return GetText() != from;
  567. }
  568.  
  569. istream& TextView::ReadFrom(istream &s)
  570. {
  571.     StaticTextView::ReadFrom(s);
  572.     GetText()->AddObserver(this);
  573.     scratchText= text->GetScratchText(cMaxBatchedIns);
  574.     return s;
  575. }
  576.  
  577. void TextView::NormSelection()
  578. {
  579.     if (start.ch > end.ch) 
  580.     SwapSelPoints(start, end);
  581. }
  582.  
  583. //---- erichsneusterhack
  584.  
  585. static ObjArray *saved;
  586. MarkList *savedMarks;
  587. static bool doSwap= FALSE;
  588. static int swapAt;
  589.  
  590. void TextView::StartFormatting()
  591. {
  592.     if (doSwap) {
  593.     // temporary replacement of the array with the line marks
  594.     saved= lines;
  595.     savedMarks= marks;
  596.     marks= new MarkList;
  597.     lines= new ObjArray(12, swapAt);
  598.     }
  599. }
  600.  
  601. int TextView::FormatInsertedText(int at, int startCh, int n)
  602. {
  603.     if (!formatter->IsKindOf(SimpleFormatter)) // ugly optimization for Simpleformatter
  604.     return 0;
  605.  
  606.     int end, upto, d;
  607.     LineMark *m;
  608.     
  609.     formatter->Preemptive(FALSE);
  610.     doSwap= TRUE;
  611.     swapAt= at;
  612.     upto= startCh + n;
  613.     end= formatter->DoIt(at, upto);
  614.     d= max(0, end - at);
  615.     swap((Object**)&saved, (Object**)&lines);
  616.     swap((Object**)&savedMarks, (Object**)&marks);
  617.     if (d > 0) {
  618.     for (int i= nLines-1; i > at; i--) { // make room for new lines
  619.         m= MarkAtLine(i);
  620.         MarkLine(i+d, m->pos, m->pos+m->len, &m->ld);
  621.     } 
  622.     for (i= at; i <= at + d; i++) {  // insert the new formatted lines
  623.         m= (LineMark*)(*saved)[i];
  624.         MarkLine(i, m->pos, m->pos+m->len, &m->ld);
  625.     }
  626.     MarkLineAsChanged(i-1);           // mark the last line as changed
  627.     }
  628.     nLines+= d; 
  629.     savedMarks->FreeAll();
  630.     delete savedMarks;
  631.     delete saved; 
  632.     InvalidateRange(at, at+d);
  633.     formatter->Preemptive(TRUE);
  634.     doSwap= FALSE;
  635.     return d;
  636. }
  637.  
  638. int TextView::DeleteLines(int from, int to)
  639. {
  640.     int d= to - from;
  641.     if (d > 0) {
  642.     for (int i= from + 1; i < nLines-d; i++) {
  643.         LineMark *m= MarkAtLine(i+d);
  644.         MarkLine(i, m->pos, m->pos+m->len, &m->ld);
  645.     } 
  646.     nLines-= d;
  647.     MarkLineAsChanged(from);
  648.     }
  649.     return d;
  650. }
  651.  
  652. void TextView::Dump()
  653. {
  654.     StaticTextView::Dump();
  655.     cerr << "Selection: start = " << start.ch << "," << start.line;
  656.     cerr << " end = " << end.ch << "," << end.line NL;
  657.     for (int i= start.ch; i < end.ch; i++)
  658.     cerr.put((*text)[i]);
  659.     cerr NL;
  660. }
  661.  
  662. //---- menu related commands -----------------------------------------------
  663.  
  664. void TextView::DoCreateMenu(Menu *mp)
  665. {
  666.     View::DoCreateMenu(mp);
  667.     if (!TestFlag(eTextNoFind)) {
  668.     char *fs= GetReadOnly() ? "find..." : "find/change...";
  669.     mp->InsertItemsAfter(cLASTEDIT, "select all",   cSELECTALL,
  670.                     fs,             cFIND,
  671.                     0);
  672.     }
  673. }
  674.  
  675. bool TextView::HasSelection()
  676. {
  677.     return AnySelection() && !Caret();
  678. }
  679.  
  680. void TextView::SelectionToClipboard(char *type, ostream &os)
  681. {
  682.     Text *t= SelectionAsText();
  683.     if (t) {
  684.     if (strcmp(type, cDocTypeET) == 0)
  685.         os << t SP;
  686.     else if (strcmp(type, cDocTypeAscii) == 0)
  687.         t->PrintOnAsPureText(os);
  688.     delete t;
  689.     }
  690. }
  691.  
  692. Command *TextView::PasteData(char *type, istream &s)
  693. {
  694.     if (strcmp(type, cDocTypeET) == 0) {
  695.     Object *op= 0;
  696.     s >> op;
  697.     if (op && op->IsKindOf(Text))
  698.         return new PasteCommand(this, (Text*)op);
  699.     } else if (strcmp(type, cDocTypeAscii) == 0)
  700.     return new PasteCommand(this, new GapText((byte*)s.bufptr()));
  701.     return gNoChanges;
  702. }
  703.  
  704. bool TextView::CanPaste(char *type)
  705. {
  706.     return strismember(type, cDocTypeET, cDocTypeAscii, 0);
  707. }
  708.  
  709. void TextView::DoSetupMenu(Menu *mp)
  710. {
  711.     View::DoSetupMenu(mp);
  712.     if (!GetReadOnly()) {
  713.     if (!Caret())
  714.         mp->EnableItem(cCUT);
  715.     if (AnySelection())
  716.         mp->EnableItem(cPASTE);
  717.     }
  718.     if (AnySelection())
  719.     mp->EnableItems(cSELECTALL, cFIND, 0);
  720. }
  721.  
  722. Command *TextView::DoMenuCommand(int cmd)
  723. {
  724.     switch (cmd) {
  725.     case cCUT:
  726.     gClipBoard->SetType((char*) cDocTypeET);
  727.     View::DoMenuCommand(cmd);
  728.     return new CutCopyCommand(this, cCUT);
  729.     case cCOPY:
  730.     gClipBoard->SetType((char*) cDocTypeET);
  731.     View::DoMenuCommand(cmd);
  732.     return new CutCopyCommand(this, cCOPY);
  733.     case cSELECTALL:
  734.     SelectAll();
  735.     break;
  736.     case cFIND:
  737.     if (findChange == 0) {
  738.         findChange= MakeFindDialog();
  739.         Document *dp= GetDocument();
  740.         if (dp)
  741.         GetDocument()->AddWindow(findChange->GetWindow());
  742.     }
  743.     findChange->ShowOnWindow(GetWindow());
  744.     return gNoChanges;
  745.     default:
  746.     return View::DoMenuCommand(cmd);
  747.     }
  748.     return gNoChanges;
  749. }
  750.  
  751. void TextView::SendDown(int id, int part, void *val)
  752. {
  753.     switch (part) {
  754.     case cPartFocusChanged:
  755.     bool dontRedraw= ((bool) val);
  756.     if (id == cIdStartKbdFocus)   
  757.         SetSelection(0, cMaxInt, !dontRedraw);
  758.     else 
  759.         SetNoSelection(!dontRedraw);
  760.     break;
  761.     case cPartHasSelection:  
  762.     *(bool*)val= HasSelection();
  763.     break;
  764.     default:
  765.     StaticTextView::SendDown(id, part, val);
  766.     }
  767. }
  768.  
  769. FindDialog *TextView::MakeFindDialog()
  770. {
  771.     if (GetReadOnly())
  772.     return new FindDialog("Find", this);
  773.     return new ChangeDialog("Find/Change", this);
  774. }
  775.  
  776. bool TextView::SelectRegExpr(RegularExp *rex, bool forward)
  777. {
  778.     int selStart, selEnd, pos, matched;
  779.  
  780.     GetSelection(&selStart, &selEnd);
  781.     if (forward)
  782.     pos= GetText()->Search(rex, &matched, selEnd);
  783.     else
  784.     pos= GetText()->Search(rex, &matched, max(0,selStart-1), cMaxInt, FALSE);
  785.  
  786.     if (pos != -1) {
  787.     SetSelection(pos, pos+matched);
  788.     return TRUE;
  789.     }
  790.     return FALSE;
  791. }
  792.  
  793. void TextView::Home()
  794. {
  795.     SetSelection(0, 0);
  796. }
  797.  
  798. void TextView::Bottom()
  799. {
  800.     SetSelection(cMaxInt, cMaxInt);
  801. }
  802.  
  803. void TextView::SelectAll()
  804. {
  805.     SetSelection(0, text->Size());
  806. }
  807.  
  808. void TextView::Enable(bool b, bool redraw)
  809. {
  810.     StaticTextView::Enable(b, redraw);
  811.     if (! Enabled())
  812.     SetNoSelection(TRUE);
  813.